<?php
/*
 *
 * 加解密
 *
 * You are not expected to understand this
 */
namespace tool;

class Crypt
{
    //加密
    static public function encrypt($text, $key = '')
    {
        return self::cryptstr($text, $key, 'encrypt');
    }

    //解密
    static public function decrypt($text, $key = '')
    {
        return self::cryptstr($text, $key, 'decrypt');
    }

    //可变可逆加解密, e=encrypt other=decrypt
    static private function cryptstr($str, $pid = '', $type = 'encrypt') //$pid  PHPSESSID
    {
        //密钥
        $aEncryptkey = array(
            '0' => 'VbPQdnCn4JYQM6DSIBLQ',
            '1' => 'VYPg5uB3MKYgU8WnVXew',
            '2' => 'cJbwRkBHBdNQkwDyBUeF',
            '3' => 'dYPgFhCn5bMwE4AS5Xew',
            '4' => 'YOaAVlVyMBaQc+WnUALA',
            '5' => 'NdOwZmVyMLYwE4DSIBLV',
            '6' => 'NfOQBgA3cIYAM6CCcEKA',
            '7' => '4LbVExVyNbMwI7W3RVeV',
            '8' => 'YBZ1Y2AHQOZgU8DCNQfA',
            '9' => 'cBZ1Y2UycNZVNqDyADLw',
            'a' => 'MLbQNjA3ddNQE4W3QBLQ',
            'b' => 'BfOVIyCn5dNQA5WHcGKg',
            'c' => 'QOaAVlA3cJYVVsX3BVeQ',
            'd' => '5bPQJiVCABaQgxCCdXew',
            'e' => 'IKbFQ0AHRaMgA5CCdVeQ',
            'f' => 'JaPANjBXEOZgA5XHNXe1',
            'g' => 'daPAFhBHALYwU8DyAGKl',
            'h' => '8BZ1ExViIAaFNqDSJTfw',
            'i' => 'YNaw5uC38MZFduCSYGKl',
            'j' => 'ZfOQdnViJbM1RtWnUALA',
            'k' => 'ZfOVQ0BnIAaAY/XHMIJF',
            'l' => 'MMagBgBHAKYlVsWHdXe1',
            'm' => 'ELbQVlAnZdNQY/AC8IJA',
            'n' => 'YOaABgVyMIYAU8CCcEKA',
            'o' => 'YBZwZmVCALYwY/XXJTf1',
            'p' => 'QPaQ9vAHQJYQQ9CSYIJA',
            'q' => 'QIbgFhBXFdNQkwAS4BLV',
            'r' => 'QAZgZmC39aMgc+AC8JJQ',
            's' => 'IJbwRkUycMZFVsCyRSfl',
            't' => 'YNa1U1VyMKYgY/CyQDLw',
            'u' => 'RaPFExBXENZVJrCSZTfw',
            'v' => 'UJbwdnBXFfN1NqCyQJJQ',
            'w' => 'UJbwBgBnINZQkwDiEIJA',
            'x' => 'ZdOwdnC38BaVNqX3ABLV',
            'y' => 'dfOQRkUycNZVJrCSYGKl',
            'z' => 'YNawZmAnYPZwA5CSZTfw',
            'A' => 'INawZmBXEIYAY/W3QIJA',
            'B' => 'EOaAJiB3NfNwc+AC9VeQ',
            'C' => 'ZYPgJiC38BaVJrDiFTfw',
            'D' => '4PaQZmAHRYMAI7XHNTf1',
            'E' => 'BfOQ5uViIPZwkwDiFXew',
            'F' => 'UJb1Y2BnJfNwQ9WHcEKA',
            'G' => 'cMagJiViJaMgE4CyRSfg',
            'H' => 'ZYPlExB3NbM1VsXHNTfw',
            'I' => '8LbQNjAXUOZlRtCCcFKQ',
            'J' => 'ILbQ9vUSUMZFVsAS4IJF',
            'K' => 'JfOVU1Cn4OZgkwCSZQfA',
            'L' => 'EKbAdnBHAPZwE4DCNQfA',
            'M' => '5fOQdnAnZdNVVsDiFVeV',
            'N' => 'MPaQFhBXEBaQI7CyRQfA',
            'O' => 'FcOgFhVyMOZgc+XXJUeF',
            'P' => 'RYPgBgUCRcNAE4DCNXe1',
            'Q' => 'RbPQRkAHRYMAE4WHdTfw',
            'R' => 'IBZ1U1AHRaMgU8XHMEKF',
            'S' => 'UAZgRkAXVaMgQ9WnVQfA',
            'T' => 'YAZg5uUCQBaQA5W3QEKA',
            'U' => '8Na1MzViJcNFRtCyQGKg',
            'V' => 'UNaw5uC39aMgI7X3BVeQ',
            'W' => 'VYPgBgUCQIYAU8CCdQfA',
            'X' => 'EIbgZmBnIOZgQ9CiVQfF',
            'Y' => 'JdO1ExBHBcNAM6DCMALF',
            'Z' => 'QKbA9vBnIIYAM6WHcIJA',
            '-' => '01Dd9b92F6a1E1Cb0063',
            '_' => 'aD153F8cb4C1E1707827',
            '.' => 'E0e637d93A14897dC590'
        );

        $ret = '';
        if ('encrypt' == $type) { //加密
            $str_len = strlen($str);
            if (1 > $str_len) {
                return '';
            }

            //生成随机密钥，附带标记
            $key_flag = array_rand($aEncryptkey);
            $key_prefix = $aEncryptkey[$key_flag];

            $key = substr(md5($key_prefix . $pid), 10, 20);
            $key_len = strlen($key);

            for ($i = 0; $i < $str_len; $i++) {
                $char = substr($str, $i, 1);
                $keychar = substr($key, ($i % $key_len) - 1, 1);
                $char = chr(ord($char) + ord($keychar));
                $ret .= $char;
            }
            $ret = str_replace(array(
                '+',
                '/',
                '='
            ), array(
                '-',
                '_',
                '.'
            ), base64_encode($ret));
            return $ret . $key_flag;
        } else { //解密
            if (2 > strlen($str)) {
                return '';
            }

            $key_flag = substr($str, -1);

            if (!array_key_exists($key_flag, $aEncryptkey)) {
                return '';
            }

            $key_prefix = $aEncryptkey[$key_flag];

            $key = substr(md5($key_prefix . $pid), 10, 20);
            $key_len = strlen($key);

            $str = substr($str, 0, -1);
            $str = str_replace(array(
                '-',
                '_',
                '.'
            ), array(
                '+',
                '/',
                '='
            ), $str);

            $str = base64_decode($str);
            if (!is_string($str) || !strlen($str)) {
                return '';
            }

            $str_len = strlen($str);
            for ($i = 0; $i < $str_len; $i++) {
                $char = substr($str, $i, 1);
                $keychar = substr($key, ($i % $key_len) - 1, 1);
                $char = chr(ord($char) - ord($keychar));
                $ret .= $char;
            }
            return $ret;
        }
    }


    //另一种加解密方式
    /**
     * @param string $string 原文或者密文
     * @param string $operation 操作(ENCODE | DECODE), 默认为 DECODE
     * @param string $key 密钥
     * @param int $expiry 密文有效期, 加密时候有效， 单位 秒，0 为永久有效
     * @return string 处理后的 原文或者 经过 base64_encode 处理后的密文
     *
     * @example
     *
     * $a = authcode('abc', 'ENCODE', 'key');
     * $b = authcode($a, 'DECODE', 'key');  // $b(abc)
     *
     * $a = authcode('abc', 'ENCODE', 'key', 3600);
     * $b = authcode('abc', 'DECODE', 'key'); // 在一个小时内，$b(abc)，否则 $b 为空
     */
    static function authcode($string, $operation = 'DECODE', $key = '', $expiry = 3600, $ckey_length = 4) {

        // 随机密钥长度 取值 0-32;
        // 加入随机密钥，可以令密文无任何规律，即便是原文和密钥完全相同，加密结果也会每次不同，增大破解难度。
        // 取值越大，密文变动规律越大，密文变化 = 16 的 $ckey_length 次方
        // 当此值为 0 时，则不产生随机密钥
        $key = md5 ( $key ? $key : 'key' ); //这里可以填写默认key值
        $keya = md5 ( substr ( $key, 0, 16 ) );
        $keyb = md5 ( substr ( $key, 16, 16 ) );
        $keyc = $ckey_length ? ($operation == 'DECODE' ? substr ( $string, 0, $ckey_length ) : substr ( md5 ( microtime () ), - $ckey_length )) : '';

        $cryptkey = $keya . md5 ( $keya . $keyc );
        $key_length = strlen ( $cryptkey );

        $string = $operation == 'DECODE' ? base64_decode ( substr ( $string, $ckey_length ) ) : sprintf ( '%010d', $expiry ? $expiry + time () : 0 ) . substr ( md5 ( $string . $keyb ), 0, 16 ) . $string;
        $string_length = strlen ( $string );

        $result = '';
        $box = range ( 0, 255 );

        $rndkey = array ();
        for($i = 0; $i <= 255; $i ++) {
            $rndkey [$i] = ord ( $cryptkey [$i % $key_length] );
        }

        for($j = $i = 0; $i < 256; $i ++) {
            $j = ($j + $box [$i] + $rndkey [$i]) % 256;
            $tmp = $box [$i];
            $box [$i] = $box [$j];
            $box [$j] = $tmp;
        }

        for($a = $j = $i = 0; $i < $string_length; $i ++) {
            $a = ($a + 1) % 256;
            $j = ($j + $box [$a]) % 256;
            $tmp = $box [$a];
            $box [$a] = $box [$j];
            $box [$j] = $tmp;
            $result .= chr ( ord ( $string [$i] ) ^ ($box [($box [$a] + $box [$j]) % 256]) );
        }

        if ($operation == 'DECODE') {
            if ((substr ( $result, 0, 10 ) == 0 || substr ( $result, 0, 10 ) - time () > 0) && substr ( $result, 10, 16 ) == substr ( md5 ( substr ( $result, 26 ) . $keyb ), 0, 16 )) {
                return substr ( $result, 26 );
            } else {
                return '';
            }
        } else {
            return $keyc . str_replace ( '=', '', base64_encode ( $result ) );
        }

    }
}